package com.xiangxiao.rpan.storage.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * @auther xiangxiao
 * @email 573768011@qq.com
 * @data 2023/10/25 15:53
 */
@Slf4j
public class PlaceholderUtils {
  private static Logger logger = LoggerFactory.getLogger(PlaceholderUtils.class);


  public static final String PLACEHOLDER_PREFIX = "${";

  public static final String PLACEHOLDER_SUFFIX = "}";

  /**
   * 解析形如 defaultValue = "${zfile.onedrive-china.redirectUri}" 这样的注解---将花括号内的部分替换成指定的propertyValue
   * 解析占位符, 将指定的占位符替换为指定的值. 变量值从 Spring 环境中获取, 如没取到, 则默认为空.
   * 必须在 Spring 环境下使用, 否则会抛出异常.
   * @param   formatStr
   *          模板字符串
   * @return  替换后的字符串
   */
  public static String resolvePlaceholdersBySpringProperties(String formatStr) {
    String placeholderName = getFirstPlaceholderName(formatStr);
    if (StrUtil.isEmpty(placeholderName)) {
      return formatStr;
    }

    // 这一步较难理解，实际上执行的是 形如 applicationContext.getEnvironment().getProperty("spring.application.name"),
    // 获取参数值的一种方式(获取spring应用中application.yml中的属性配置值)
    String propertyValue = SpringUtil.getProperty(placeholderName);
    Map<String, String> map = new HashMap<>();
    map.put(placeholderName, propertyValue);
    return resolvePlaceholders(formatStr, map);
  }

  /**
   * 解析占位符, 将指定的占位符替换为指定的值.
   * @param   formatStr
   *          模板字符串
   * @param   parameter
   *          参数列表
   * @return  替换后的字符串
   */
  public static String resolvePlaceholders(String formatStr, Map<String, String> parameter) {
    StringBuffer buf = new StringBuffer(formatStr);
    int startIndex = buf.indexOf(PLACEHOLDER_PREFIX);
    while (startIndex != -1) {
      int endIndex = buf.indexOf(PLACEHOLDER_SUFFIX, startIndex + PLACEHOLDER_PREFIX.length());
      if (endIndex != -1) {
        String placeholder = buf.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex);
        int nextIndex = endIndex + PLACEHOLDER_SUFFIX.length();
        try {
          String propVal = parameter.get(placeholder);
          if (propVal != null) {
            buf.replace(startIndex, endIndex + PLACEHOLDER_SUFFIX.length(), propVal);
            nextIndex = startIndex + propVal.length();
          } else {
            logger.warn("Could not resolve placeholder '{}' in [{}] ", placeholder, formatStr);
          }
        } catch (Exception ex) {
          logger.error("Could not resolve placeholder '{}' in [{}]: ", placeholder, formatStr, ex);
        }
        startIndex = buf.indexOf(PLACEHOLDER_PREFIX, nextIndex);
      } else {
        startIndex = -1;
      }
    }
    return buf.toString();
  }

  /**
   * 获取模板字符串第一个占位符的名称, 如 "我的名字是: ${name}, 我的年龄是: ${age}", 返回 "name".
   * @param   formatStr
   *          模板字符串
   * @return  占位符名称
   */
  public static String getFirstPlaceholderName(String formatStr) {
    List<String> list = getPlaceholderNames(formatStr);
    if (CollUtil.isNotEmpty(list)) {
      return list.get(0);
    }
    return null;
  }

  /**
   * 获取模板字符串第一个占位符的名称, 如 "我的名字是: ${name}, 我的年龄是: ${age}", 返回 ["name", "age].
   * @param   formatStr
   *          模板字符串
   * @return  占位符名称
   */
  public static List<String> getPlaceholderNames(String formatStr) {
    if (StrUtil.isEmpty(formatStr)) {
      return Collections.emptyList();
    }

    List<String> placeholderNameList = new ArrayList<>();

    StringBuffer buf = new StringBuffer(formatStr);
    int startIndex = buf.indexOf(PLACEHOLDER_PREFIX);
    while (startIndex != -1) {
      int endIndex = buf.indexOf(PLACEHOLDER_SUFFIX, startIndex + PLACEHOLDER_PREFIX.length());
      if (endIndex != -1) {
        String placeholder = buf.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex);
        int nextIndex = endIndex + PLACEHOLDER_SUFFIX.length();
        startIndex = buf.indexOf(PLACEHOLDER_PREFIX, nextIndex);
        placeholderNameList.add(placeholder);
      } else {
        startIndex = -1;
      }
    }
    return placeholderNameList;
  }
}

